﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace XNAGraffiti
{
    public abstract class Graffiti
    {
        private Game m_game;
        private float m_cameraArc = -5;
        private float m_cameraRotation = 0;
        private float m_cameraDistance = 200;

        protected Graffiti(Game game)
        {
            m_game = game;
        }

        protected Game Game
        {
            get { return m_game; }
        }

        protected float CameraArc
        {
            get { return m_cameraArc; }
            set { m_cameraArc = value; }
        }

        protected float CameraRotation
        {
            get { return m_cameraRotation; }
            set { m_cameraRotation = value; }
        }

        protected float CameraDistance
        {
            get { return m_cameraDistance; }
            set { m_cameraDistance = value; }
        }

        public abstract void DrawLine(Point? startPoint, Point? endPoint);
        public abstract void Draw(GameTime gameTime);

        protected Point[] GetLinePoints(Point startPoint, Point endPoint)
        {
            var points = new List<Point>();
            int x0 = startPoint.X;
            int y0 = startPoint.Y;
            int x1 = endPoint.X;
            int y1 = endPoint.Y;

            int dx = x1 - x0;
            int dy = y1 - y0;

            if (dx != 0)
            {
                float m = (float)dy / (float)dx;
                float b = y0 - m * x0;
                dx = (x1 > x0) ? 1 : -1;
                while (x0 != x1)
                {
                    x0 += dx;
                    y0 = (int)Math.Round(m * x0 + b);
                    points.Add(new Point(x0, y0));
                }
            }
            else
                points.Add(startPoint);

            return points.ToArray();
        }

        protected Vector3 ScreenPointToVector3(Point coords)
        {
            Matrix viewMatrix = Matrix.CreateTranslation(0, -25, 0) *
                                Matrix.CreateRotationY(MathHelper.ToRadians(CameraRotation)) *
                                Matrix.CreateRotationX(MathHelper.ToRadians(CameraArc)) *
                                Matrix.CreateLookAt(new Vector3(0, 0, -CameraDistance),
                                                    new Vector3(0, 0, 0), Vector3.Up);

            float aspectRatio = (float)m_game.GraphicsDevice.Viewport.Width /
                                (float)m_game.GraphicsDevice.Viewport.Height;

            Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
                                                                    aspectRatio,
                                                                    1, 10000);

            Vector3 nearScreenPoint = new Vector3(coords.X, coords.Y, 0);
            Vector3 farScreenPoint = new Vector3(coords.X, coords.Y, 1);
            Vector3 nearWorldPoint = m_game.GraphicsDevice.Viewport.Unproject(nearScreenPoint, projectionMatrix, viewMatrix, Matrix.Identity);
            Vector3 farWorldPoint = m_game.GraphicsDevice.Viewport.Unproject(farScreenPoint, projectionMatrix, viewMatrix, Matrix.Identity);

            Vector3 direction = farWorldPoint - nearWorldPoint;

            float zFactor = -nearWorldPoint.Z / direction.Z;
            Vector3 zeroWorldPoint = nearWorldPoint + direction * zFactor;
            return zeroWorldPoint;
        }
    }
}
